package dk.itu.spvc.tourtracker.gui;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.location.Location;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

public class LocationOverlay extends ItemizedOverlay<OverlayItem> {

	// PRIVATE FIELDS
	
	// Debug
	//private static final String TAG = "TourTracker";
	//private static final boolean D = true;

	private Location location;	
	private Drawable defaultMarker;	
	private Paint accuracyStrokePaint;
	private Paint accuracyFillPaint;	
	private float longitudeLineDistance = 0.0f;
	
	private final List<OverlayItem> overlays = new ArrayList<OverlayItem>();
	
	private Runnable firstFixRunnable = null;
	private boolean doFirstFixRun = true;
	
	// CTOR
	
	public LocationOverlay(Drawable defaultMarker) {
		super(boundCenter(defaultMarker));
		populate();
		
		this.defaultMarker = defaultMarker;
		
		accuracyStrokePaint = new Paint();
		accuracyStrokePaint.setDither(true);
		accuracyStrokePaint.setAntiAlias(true);
		accuracyStrokePaint.setStrokeWidth(2.0f);
		accuracyStrokePaint.setColor(Color.BLUE);
		accuracyStrokePaint.setAlpha(50);
		accuracyStrokePaint.setStyle(Style.STROKE);
		
		accuracyFillPaint = new Paint();
		accuracyFillPaint.setDither(true);
		accuracyFillPaint.setAntiAlias(true);
		accuracyFillPaint.setStrokeWidth(2.0f);
		accuracyFillPaint.setColor(Color.BLUE);
		accuracyFillPaint.setAlpha(18);
		accuracyFillPaint.setStyle(Style.FILL);
		
	}

	// OVERRIDES
	
	@Override
	public void draw(Canvas canvas, MapView mapView, boolean shadow) {
		
		if (location == null) return;
		
		Projection projection = mapView.getProjection();
		
		double lat = location.getLatitude();
		double lng = location.getLongitude();
		
		Point locationPoint = new Point();
		Point marginalPoint = new Point();
		
		GeoPoint locationGeoPoint = new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
		GeoPoint marginalGeoPoint = new GeoPoint((int) (lat * 1E6), (int) ((lng - location.getAccuracy() / getLongitudeLineDistance()) * 1E6));		
		
		projection.toPixels(locationGeoPoint, locationPoint);
		projection.toPixels(marginalGeoPoint, marginalPoint);
		
		int radius = (locationPoint.x - marginalPoint.x) / 2;

		canvas.drawCircle(locationPoint.x, locationPoint.y, radius, accuracyStrokePaint);		
		canvas.drawCircle(locationPoint.x, locationPoint.y, radius, accuracyFillPaint);

		int w = defaultMarker.getIntrinsicWidth();
		int h = defaultMarker.getIntrinsicHeight();
		
		defaultMarker.setBounds(locationPoint.x - w / 2, locationPoint.y - h / 2, locationPoint.x + w / 2, locationPoint.y + h / 2);
		defaultMarker.draw(canvas);		
	}
	
	@Override
	protected OverlayItem createItem(int i) {
		return overlays.get(i);
	}

	@Override
	public int size() {
		return overlays.size();
	}	
	
	// METHODS

	public void setLocation (Location location) {
		
		this.location = location;
		
		// Execute first fix runnable
		executeFirstFixRunnable();
		
		// New overlay item
		GeoPoint geoPoint = new GeoPoint((int) (location.getLatitude() * 1E6), (int) (location.getLongitude() / 1E6));
		OverlayItem overlayItem = new OverlayItem(geoPoint, "Location", null);
		overlayItem.setMarker(defaultMarker);
		
		// Replace overlays
		overlays.clear();
		overlays.add(overlayItem);
		populate();
	}
	
	
	public Location getLocation ()
	{
		return location;
	}
	
	private float getLongitudeLineDistance() {	
		
		if (longitudeLineDistance == 0.0f) {	
			double lat = location.getLatitude();
			double lng = location.getLongitude();			
			float[] result = new float[1];
			Location.distanceBetween(lat, lng, lat, lng + 1, result);		
			longitudeLineDistance = result[0];			
		}
		
		return longitudeLineDistance;
	}
	
	public boolean runOnFirstFix(Runnable runnable) {

		if (location != null) {
			runnable.run();
			doFirstFixRun = false;
			return true;
		}

		firstFixRunnable = runnable;
		return false;

	}
	
	private void executeFirstFixRunnable() {
		if (doFirstFixRun && location != null && firstFixRunnable != null) {
			firstFixRunnable.run();
			doFirstFixRun = false;;
		}
	}
	
}
